/*
* Author: Chris Seguin
*
* This software has been developed under the copyleft
* rules of the GNU General Public License. Please
* consult the GNU General Public License for more
* details about use and distribution of this software.
*/
package org.acm.seguin.refactor.field;
import java.util.Iterator;
import java.util.LinkedList;
import org.acm.seguin.parser.ast.ASTName;
import org.acm.seguin.parser.ast.SimpleNode;
import org.acm.seguin.refactor.AddImportTransform;
import org.acm.seguin.refactor.ComplexTransform;
import org.acm.seguin.refactor.RefactoringException;
import org.acm.seguin.summary.FileSummary;
import org.acm.seguin.summary.PackageSummary;
import org.acm.seguin.summary.TypeDeclSummary;
import org.acm.seguin.summary.TypeSummary;
import org.acm.seguin.summary.query.FieldQuery;
import org.acm.seguin.summary.query.GetTypeSummary;
/**
* Performs the push down field refactoring
*
*@author Chris Seguin
*/
public class PushDownFieldRefactoring extends FieldRefactoring {
private LinkedList childTypes;
/**
* Constructor for the PushDownFieldRefactoring object
*/
protected PushDownFieldRefactoring()
{
childTypes = new LinkedList();
field = null;
typeSummary = null;
}
/**
* Gets the description of the refactoring
*
*@return the description
*/
public String getDescription()
{
return "Moves a field " + field +
" into child classes of " + typeSummary.getName();
}
/**
* Gets the ID attribute of the PushDownFieldRefactoring object
*
*@return The ID value
*/
public int getID()
{
return PUSH_DOWN_FIELD;
}
/**
* Adds a child class where the field should be pushed into
*
*@param packageName the package name
*@param className the class name
*/
public void addChild(String packageName, String className)
{
addChild(GetTypeSummary.query(
PackageSummary.getPackageSummary(packageName),
className));
}
/**
* Adds a child class where the field should be pushed into
*
*@param init The new Class value
*/
public void addChild(TypeSummary init)
{
if (init != null) {
System.out.println("Adding " + init.getName());
childTypes.add(init);
}
}
/**
* Preconditions that must be true for the refactoring to work
*
*@exception RefactoringException a problem with performing this
* refactoring
*/
protected void preconditions() throws RefactoringException
{
if (field == null) {
throw new RefactoringException("No field specified");
}
if (typeSummary == null) {
throw new RefactoringException("No type specified");
}
if (childTypes.size() == 0) {
throw new RefactoringException("No child types specified");
}
if (FieldQuery.query(typeSummary, field, FieldQuery.PRIVATE) == null) {
throw new RefactoringException("Field named " + field + " does not exist in " + typeSummary.getName());
}
if (((FileSummary) typeSummary.getParent()).getFile() == null) {
throw new RefactoringException("Can't push down a field from source code that you don't have");
}
Iterator iter = childTypes.iterator();
while (iter.hasNext()) {
TypeSummary next = (TypeSummary) iter.next();
if (next == null) {
throw new RefactoringException("Can't push down a field into source code that you don't have");
}
if (FieldQuery.query(next, field, FieldQuery.PRIVATE) != null) {
throw new RefactoringException("Field named " + field + " already exists in " + next.getName());
}
if (((FileSummary) next.getParent()).getFile() == null) {
throw new RefactoringException("Can't push up a field into source code that you don't have");
}
TypeDeclSummary parentDecl = next.getParentClass();
TypeSummary parentTypeSummary = GetTypeSummary.query(parentDecl);
if (parentTypeSummary != typeSummary) {
throw new RefactoringException("Trying to push a field from " +
typeSummary.getName() + " to " + next.getName() +
" and the destination is not a subclass of the source");
}
}
}
/**
* Actually update the files
*/
protected void transform()
{
FileSummary fileSummary = (FileSummary) getFileSummary(typeSummary);
RemoveFieldTransform rft = new RemoveFieldTransform(field);
ComplexTransform transform = getComplexTransform();
transform.add(rft);
transform.apply(fileSummary.getFile(), fileSummary.getFile());
// Update the field declaration to have the proper permissions
SimpleNode fieldDecl = rft.getFieldDeclaration();
if (fieldDecl == null) {
return;
}
Iterator iter = childTypes.iterator();
while (iter.hasNext()) {
AddFieldTransform aft = new AddFieldTransform(fieldDecl);
transform.clear();
transform.add(aft);
Object fieldType = getFieldType(fieldDecl, fileSummary);
if (fieldType == null) {
// Do nothing
}
else if ((fieldType instanceof TypeSummary) &&
!isInJavaLang((TypeSummary) fieldType)) {
transform.add(new AddImportTransform((TypeSummary) fieldType));
}
else if ((fieldType instanceof ASTName) &&
!isInJavaLang((ASTName) fieldType)) {
transform.add(new AddImportTransform((ASTName) fieldType));
}
TypeSummary next = (TypeSummary) iter.next();
FileSummary nextFileSummary = (FileSummary) next.getParent();
transform.apply(nextFileSummary.getFile(), nextFileSummary.getFile());
}
}
}